# -*- mode: Perl -*-
# /=====================================================================\ #
# |  diagbox                                                            | #
# | Implementation for LaTeXML                                          | #
# |=====================================================================| #
# | Part of LaTeXML:                                                    | #
# |  Public domain software, produced as part of work done by the       | #
# |  United States Government & not subject to copyright in the US.     | #
# |---------------------------------------------------------------------| #
# | Bruce Miller <bruce.miller@nist.gov>                        #_#     | #
# | http://dlmf.nist.gov/LaTeXML/                              (o o)    | #
# \=========================================================ooo==U==ooo=/ #
package LaTeXML::Package::Pool;
use strict;
use warnings;
use LaTeXML::Package;
#======================================================================
DefKeyVal('diagbox', 'dir',           '');
DefKeyVal('diagbox', 'width',         'Dimension');
DefKeyVal('diagbox', 'height',        'Dimension');
DefKeyVal('diagbox', 'innerwidth',    'Dimension');
DefKeyVal('diagbox', 'innerleftsep',  'Dimension');    # ignored
DefKeyVal('diagbox', 'innerrightsep', 'Dimension');    # ignored
DefKeyVal('diagbox', 'outerleftsep',  'Dimension');    # ignored
DefKeyVal('diagbox', 'outerrightsep', 'Dimension');    # ignored
DefKeyVal('diagbox', 'leftsep',       'Dimension');    # ignored
DefKeyVal('diagbox', 'rightsep',      'Dimension');    # ignored
DefKeyVal('diagbox', 'trim',          '');             # ignored
DefKeyVal('diagbox', 'font',          '');
DefKeyVal('diagbox', 'linewidth',     '');
DefKeyVal('diagbox', 'linecolor',     '');

# NOTE that this macro SNIFFS out an optional 3rd argument!!!
# Possibly should turn off guess headers in containing alignment?
DefMacro('\diagbox OptionalKeyVals:diagbox {}{}', sub {
    my ($gullet, $kv, $A, $B) = @_;
    my $M;
    if ($gullet->ifNext(T_BEGIN)) {
      $M = $B; $B = $gullet->readArg; }
    my $dir = $kv && ToString($kv->getValue('dir')) || 'NW';
    if ($dir) {
    }
    my $font = $kv && $kv->getValue('font');
    return Invocation(T_CS('\lx@diagbox'),
      $kv,
      Invocation(T_CS('\lx@diagbox@head'), T_LETTER('l'), $font, $A),
      $M && Invocation(T_CS('\lx@diagbox@head'), T_LETTER(($dir =~ /W/ ? 'l' : 'r')), $font, $M),
      Invocation(T_CS('\lx@diagbox@head'), T_LETTER('r'), $font, $B)); });

DefMacro('\lx@diagbox@head{}{}{}', '{#2\shortstack[#1]{#3}}');

DefConstructor('\lx@diagbox RequiredKeyVals:diagbox {}[]{}',
  "<ltx:picture width='&pxValue(#width)' height='&pxValue(#height)'>"
    . "?#line1(<ltx:line points='#line1' stroke='#linecolor' stroke-width='#linewidth'/>)()"
    . "?#line2(<ltx:line points='#line2' stroke='#linecolor' stroke-width='#linewidth'/>)()"
    . "<ltx:g transform='translate(#Ax,#Ay)'"
    . " innerwidth='#Aw' innerheight='#Ah' innerdepth='#Ad' class='ltx_svg_fog'>"
    . "<ltx:inline-block>#A</ltx:inline-block>"
    . "</ltx:g>"
    . "<ltx:g transform='translate(#Bx,#By)'"
    . " innerwidth='#Bw' innerheight='#Bh' innerdepth='#Bd' class='ltx_svg_fog'>"
    . "<ltx:inline-block>#B</ltx:inline-block>"
    . "</ltx:g>"
    . "?#M(<ltx:g transform='translate(#Mx,#My)'"
    . " innerwidth='#Mw' innerheight='#Mh' innerdepth='#Md' class='ltx_svg_fog'>"
    . "<ltx:inline-block>#M</ltx:inline-block>"
    . "</ltx:g>)()"
    . "</ltx:picture>",
  afterConstruct => sub { $_[0]->addClass($_[0]->getNode, 'ltx_nopad'); },
  reversion      => '\diagbox[#1]{#2}{#4}{#3}',                              # Wrong!
  afterDigest    => sub {
    my ($stomach, $whatsit) = @_;
    # Annoying: All svg units, and computations, are in pixels!
    my ($kv, $A, $M, $B) = $whatsit->getArgs;
    my $dir = $kv && ToString($kv->getValue('dir')) || 'NW';
    my ($Aw, $Ah, $Ad) = map       { roundto($_->pxValue) } $A->getSize; $Ah += $Ad;
    my ($Bw, $Bh, $Bd) = map       { roundto($_->pxValue) } $B->getSize; $Bh += $Bd;
    my ($Mw, $Mh, $Md) = $M && map { roundto($_->pxValue) } $M->getSize; $Mh += $Md if $Mh;
    my $maxw = max($Aw, $Bw);
    my $maxh = max($Ah, $Bh);
    my $w    = $kv && ($kv->getValue('width') || $kv->getValue('innerwidth'));
    my $h    = $kv && $kv->getValue('height');
    my ($line1, $line2);
    my ($Ax, $Ay, $Bx, $By, $Mx, $My) = (0, 0, 0, 0, 0, 0);
    $w = $w->pxValue if $w;
    $h = $h->pxValue if $h;
    ## See diagbox.pdf under Implementation
    if ($M) {
      if (!($w && $h)) {    # size given, no need for fancy calculations
        my $t     = $Ah + $Mh;
        my $s     = $Bw + $Mw;
        my $v     = $s * $t - $Aw * $Bh;
        my $u     = $Aw * $Mh - $Mw * $Bh;
        my $delta = ($u + $v) * ($u + $v) + 4 * $Aw * ($t - $Bh) * ($Mw * ($Bh - $Mh) - $Bw * $Mh);
        $w = (($Bh < $t) && ($delta >= 0)
          ? ($u + $v + sqrt($delta)) / ($t - $Bh) / 2
          : 2 * (max($Aw, $Bw) + $Mw)) unless $w;
        $h = (($Aw < $s) && ($delta >= 0)
          ? ($u - $v - sqrt($delta)) / ($Aw - $s) / 2
          : 2 * (max($Ah, $Bh) + $Mh)) unless $h; }
      $w = roundto($w);
      $h = roundto($h);
      my ($wm, $hm) = ($w * 0.5, $h * 0.5);
      if ($dir eq 'NW') {
        $My    = $h - $Mh;
        $Bx    = $w - $Bw;
        $By    = $h - $Bh;
        $line1 = "$wm,$h $w,0";
        $line2 = "0,$hm $w,0"; }
      elsif ($dir eq 'SE') {
        $Mx    = $w - $Mw;
        $Bx    = $w - $Bw;
        $By    = $h - $Bh;
        $line1 = "0,$h $w,$hm";
        $line2 = "0,$h $wm,0"; }
      elsif ($dir eq 'SW') {
        $Ay    = $h - $Ah;
        $Bx    = $w - $Bw;
        $line1 = "0,$hm $w,$h";
        $line2 = "$wm,0 $w,$h"; }
      elsif ($dir eq 'NE') {
        $Ay    = $h - $Ah;
        $Mx    = $w - $Mw;
        $My    = $h - $Mh;
        $Bx    = $w - $Bw;
        $line1 = "0,0 $wm,$h";
        $line2 = "0,0 $w,$hm"; } }
    else {
      $w  = 2 * $maxw unless $w;
      $h  = $Ah + $Bh unless $h;
      $w  = roundto($w);
      $h  = roundto($h);
      $Bx = $w - $Bw;
      if (($dir eq 'NW') || ($dir eq 'SE')) {
        $By    = $h - $Bh;
        $line1 = "0,$h $w,0"; }
      else {
        $Ay    = $h - $Ah;
        $line1 = "0,0, $w,$h"; } }
    my $pxppt = Dimension('1pt')->pxValue(10);
    $whatsit->setProperties(
      width     => Dimension($w / $pxppt . 'pt'), height => Dimension($h / $pxppt . 'pt'),
      A         => $A,     Ax    => $Ax, Ay => $Ay, Aw => $Aw, Ah => $Ah,
      B         => $B,     Bx    => $Bx, By => $By, Bw => $Bw, Bh => $Bh,
      M         => $M,     Mx    => $Mx, My => $My, Mw => $Bw, Mh => $Mh,
      line1     => $line1, line2 => $line2,
      linewidth => ($kv && $kv->getValue('linewidth')) || '0.4',
      linecolor => ($kv && $kv->getValue('linecolor')) || 'black'); }
);

# slashbox compatibility
DefMacro('\slashbox[][]{}{}',
  '\def\@tempa{dir=SW}'
    . '\ifx.#1.\else\edef\@tempa{\@tempa,width={#1}}\fi'
    . '\ifx.#2.\else\edef\@tempa{\@tempa,trim={#2}}\fi'
    . '\diagbox[\@tempa]{#3}{#4}');
DefMacro('\backslashbox[][]{}{}',
  '\def\@tempa{dir=NW}'
    . '\ifx.#1.\else\edef\@tempa{\@tempa,width={#1}}\fi'
    . '\ifx.#2.\else\edef\@tempa{\@tempa,trim={#2}}\fi'
    . '\diagbox[\@tempa]{#3}{#4}');

#======================================================================
1;
